// Example client-side code for handling streaming responses
import { invoke } from '@tauri-apps/api/tauri';

class StreamingClient {
  constructor() {
    this.activeStreams = new Map();
  }

  async makeRequest(uri, method = 'GET', body = null, headers = {}) {
    const localRequest = {
      uri,
      method,
      body,
      headers
    };

    try {
      const result = await invoke('handle_app_request', { localRequest });

      if (result.type === 'streaming') {
        return this.handleStreamingResponse(result);
      } else {
        return this.handleRegularResponse(result);
      }
    } catch (error) {
      console.error('Request failed:', error);
      throw error;
    }
  }

  handleRegularResponse(result) {
    return {
      type: 'regular',
      statusCode: result.status_code,
      body: new TextDecoder().decode(new Uint8Array(result.body)),
      headers: result.headers
    };
  }

  async handleStreamingResponse(result) {
    const streamId = result.stream_id;
    const stream = new ReadableStream({
      start: (controller) => {
        this.activeStreams.set(streamId, controller);
        this.readStreamChunks(streamId, controller);
      },
      cancel: () => {
        this.closeStream(streamId);
      }
    });

    return {
      type: 'streaming',
      statusCode: result.status_code,
      headers: result.headers,
      streamId,
      stream
    };
  }

  async readStreamChunks(streamId, controller) {
    try {
      while (true) {
        const chunk = await invoke('get_stream_chunk', { streamId });

        if (!chunk) {
          // Stream ended
          controller.close();
          this.activeStreams.delete(streamId);
          break;
        }

        if (chunk.data.length > 0) {
          const data = new Uint8Array(chunk.data);
          controller.enqueue(data);
        }

        if (chunk.is_final) {
          controller.close();
          this.activeStreams.delete(streamId);
          break;
        }
      }
    } catch (error) {
      console.error('Stream reading error:', error);
      controller.error(error);
      this.activeStreams.delete(streamId);
    }
  }

  async closeStream(streamId) {
    try {
      await invoke('close_stream', { streamId });
      const controller = this.activeStreams.get(streamId);
      if (controller) {
        controller.close();
        this.activeStreams.delete(streamId);
      }
    } catch (error) {
      console.error('Error closing stream:', error);
    }
  }

  // Helper method for Server-Sent Events
  async createEventSource(uri) {
    const response = await this.makeRequest(uri);

    if (response.type !== 'streaming') {
      throw new Error('Expected streaming response for EventSource');
    }

    const reader = response.stream.getReader();
    const decoder = new TextDecoder();

    return {
      addEventListener: (type, callback) => {
        if (type === 'message') {
          this.readEvents(reader, decoder, callback);
        }
      },
      close: () => {
        reader.cancel();
        this.closeStream(response.streamId);
      }
    };
  }

  async readEvents(reader, decoder, callback) {
    try {
      while (true) {
        const { done, value } = await reader.read();

        if (done) break;

        const text = decoder.decode(value, { stream: true });
        const lines = text.split('\n');

        for (const line of lines) {
          if (line.startsWith('data: ')) {
            const data = line.substring(6);
            callback({ data });
          }
        }
      }
    } catch (error) {
      console.error('Event reading error:', error);
    }
  }
}

// Usage examples:
export async function exampleUsage() {
  const client = new StreamingClient();

  // Regular request
  const regularResponse = await client.makeRequest('/');
  console.log('Regular response:', regularResponse.body);

  // Streaming request
  const streamingResponse = await client.makeRequest('/stream');
  if (streamingResponse.type === 'streaming') {
    const reader = streamingResponse.stream.getReader();
    const decoder = new TextDecoder();

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      const text = decoder.decode(value);
      console.log('Stream chunk:', text);
    }
  }

  // Server-Sent Events
  const eventSource = await client.createEventSource('/events');
  eventSource.addEventListener('message', (event) => {
    console.log('SSE event:', event.data);
  });

  // Close after 10 seconds
  setTimeout(() => {
    eventSource.close();
  }, 10000);
}

export default StreamingClient;
